package com.ctiot.custom.oauth.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.Feature;
import com.ctiot.custom.oauth.api.CustomApi;
import com.ctiot.custom.oauth.model.AccessToken;
import com.ctiot.custom.oauth.model.CheckToken;
import com.ctiot.custom.oauth.model.CustomResponse;
import com.ctiot.custom.oauth.model.UserInfo;
import com.ctiot.custom.oauth.service.CustomOAuthService;
import org.scribe.exceptions.OAuthException;
import org.scribe.model.OAuthConfig;
import org.scribe.model.OAuthRequest;
import org.scribe.model.Response;
import org.scribe.model.Token;
import org.scribe.model.Verb;
import org.scribe.model.Verifier;
import org.scribe.oauth.OAuth20ServiceImpl;

import java.lang.reflect.Type;
import java.util.Objects;

/**
 * @projectName: oauth-sdk-bim
 * @packageName: com.ctiot.bim.oauth.service.impl
 * @description:
 * @author: huayang.bai
 * @date: 2021-04-12 10:50
 */
public class CustomOAuthServiceImpl extends OAuth20ServiceImpl implements CustomOAuthService {

    private final CustomApi customApi;

    private final OAuthConfig config;

    public CustomOAuthServiceImpl(CustomApi customApi, OAuthConfig config) {
        super(customApi, config);
        this.customApi = customApi;
        this.config = config;
    }


    @Override
    public Token getAccessToken(Token requestToken, Verifier verifier) {
        OAuthRequest request = new OAuthRequest(Verb.POST, this.customApi.getAccessTokenEndpoint());
        request.addQuerystringParameter("X-APP-ID", customApi.getxAppId());
        request.addQuerystringParameter("X-APP-KEY", customApi.getxAppKey());
        request.addQuerystringParameter("client_id", this.config.getApiKey());
        request.addQuerystringParameter("client_secret", this.config.getApiSecret());
        request.addQuerystringParameter("code", verifier.getValue());
        request.addQuerystringParameter("grant_type", "authorization_code");
//        request.addQuerystringParameter("redirect_uri", this.config.getCallback());
//        if (this.config.hasScope()) {
//            request.addQuerystringParameter("scope", this.config.getScope());
//        }
        Response response = request.send();
        return this.customApi.getAccessTokenExtractor().extract(response.getBody());
    }

    @Override
    public AccessToken getAccessToken(String code) {
        Token token = this.getAccessToken(null, new Verifier(code));
        if (Objects.equals("", token.getToken())) {
            throw new OAuthException("Get access_token failed");
        } else {
            // todo gitee中，缺少信息
//            AccessToken accessToken = new AccessToken();
//            accessToken.setAccessToken(token.getToken());
//            return accessToken;
            return JSONObject.parseObject(token.getRawResponse(), AccessToken.class);
        }
    }

    @Override
    public CheckToken checkAccessToken(String accessToken) {
        OAuthRequest request = new OAuthRequest(Verb.GET, customApi.getCheckTokenEndpoint());
        request.addQuerystringParameter("X-APP-ID", customApi.getxAppId());
        request.addQuerystringParameter("X-APP-KEY", customApi.getxAppKey());
        request.addQuerystringParameter("access_token", accessToken);
        Response response = request.send();
        String responceBody = response.getBody();
        CustomResponse<CheckToken> checkTokenAepResponse = this.parseResponse(responceBody, CheckToken.class);
        if (checkTokenAepResponse.isOK()) {
            return checkTokenAepResponse.getData();
        } else {
            throw new OAuthException("Check access_token failed:" + checkTokenAepResponse.getReason());
        }
    }

    @Override
    public AccessToken refreshAccessToken(String refreshToken) {
        OAuthRequest request = new OAuthRequest(this.customApi.getAccessTokenVerb(), customApi.getRefreshTokenEndpoint());
        request.addQuerystringParameter("X-APP-ID", customApi.getxAppId());
        request.addQuerystringParameter("X-APP-KEY", customApi.getxAppKey());
        request.addQuerystringParameter("client_id", this.config.getApiKey());
        request.addQuerystringParameter("client_secret", this.config.getApiSecret());
        request.addQuerystringParameter("refresh_token", refreshToken);
        request.addQuerystringParameter("grant_type", "refresh_token");
        Response response = request.send();
        String responceBody = response.getBody();
        CustomResponse<AccessToken> bimResponse = this.parseResponse(responceBody, AccessToken.class);
        if (bimResponse.isOK()) {
            return bimResponse.getData();
        } else {
            throw new OAuthException("Check access_token failed:" + bimResponse.getReason());
        }
    }

    @Override
    public UserInfo getUserInfo(String accessToken) {
        OAuthRequest request = new OAuthRequest(Verb.GET, this.customApi.getUserInfoUrl());
        request.addQuerystringParameter("X-APP-ID", customApi.getxAppId());
        request.addQuerystringParameter("X-APP-KEY", customApi.getxAppKey());
        request.addQuerystringParameter("access_token", accessToken);
        request.addQuerystringParameter("client_id", this.config.getApiKey());
        Response response = request.send();
        String responseBody = response.getBody();
        UserInfo userInfo = JSONObject.parseObject(responseBody, UserInfo.class);
        return userInfo;
    }


    private <T> CustomResponse<T> parseResponse(String json, Class<T> clazz) {
        return JSONObject.parseObject(json, new TypeReference<CustomResponse<T>>(new Type[]{clazz}) {
        }, new Feature[0]);
    }

    public CustomApi getCustomApi() {
        return customApi;
    }
}
